﻿//
// File: Queue.cs
//
// Purpose: implements queue collection classes.
//          blocking and nonblocking queue
//
// Author: MotherHacker @ cachecleaner.codeplex.com

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace QueuedOperation
{

    public interface IQueue<T> : ICollection<T>, IEnumerable<T>
    {
        void Enqueue(T item);
        T    Dequeue();
    }

    #region NonBlockingQueue<T> implementation of IQueue<T>
    public class NonBlockingQueue<T> : IQueue<T>
    {
        Node head, tail;
        object h_lock, t_lock;
        int count;

        #region node structure

        class Node
        {
            public T value;
            public Node next;

            public Node() { }

            public Node(T value)
            {
                this.value = value;
            }
        }

        #endregion

        public NonBlockingQueue()
        {
            Node root = new Node();
            root.next = null;

            head = tail = root;
            h_lock = t_lock = new object();
            count = 0;

        }

        #region IQueue<T> Members

        public void Enqueue(T item)
        {
            lock (t_lock) // lock tail of the queue
            {
                Node node = new Node(item);

                tail.next = node;
                tail = node;

                Interlocked.Increment(ref count);
            }
        }

        public T Dequeue()
        {
            lock (h_lock) // lock head of the queue
            {
                Node node = head.next;

                if (null == node)
                    return default(T);

                T value = node.value;
                head = node;

                node.value = default(T); // remove ref.

                Interlocked.Decrement(ref count);

                return value;
            }
            
        }

        #endregion

        #region ICollection<T> Members

        void ICollection<T>.Add(T item)
        {
            Enqueue(item);
        }

        public void Clear()
        {            
            lock (h_lock)
            {
                lock (t_lock)
                {

                    Node root = new Node();
                    root.next = null;

                    head = tail = root;
                    count = 0;
                }
            }
        }

        bool ICollection<T>.Contains(T item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            foreach (T item in this)
            {
                array[arrayIndex++] = item;
            }
        }

        public int Count
        {
            get { return count; }
        }

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<T>.Remove(T item)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            while ( count > 0 ) yield return Dequeue();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
    #endregion

    #region BlockingQueue<T> implementation of IQueue<T>
    /// <summary>
    /// Blocks when attempt to dequeue when queue is empty.
    /// </summary>
    public class BlockingQueue<T> : IQueue<T>
    {
        private NonBlockingQueue<T> queue;
        private int count;


        public BlockingQueue()
        {
            queue = new NonBlockingQueue<T>();
            count = 0;

        }
        #region IQueue<T> Members

        public void Enqueue(T item)
        {
            lock (queue)
            {
                queue.Enqueue(item);
                Interlocked.Increment(ref count);
                Monitor.Pulse(queue);
            }
        }


        /// <summary>
        /// Blocks if queue is empty.
        /// </summary>
        public T Dequeue()
        {
            lock (queue)
            {
                while (count <= 0) Monitor.Wait(queue);
                Interlocked.Decrement(ref count);
                return queue.Dequeue();
            }
        }

        #endregion

        #region ICollection<T> Members

        void ICollection<T>.Add(T item)
        {
            Enqueue(item);
        }

        public void Clear()
        {
            queue.Clear();
            count = 0;

        }

        public bool Wait(int timeout)
        {
            lock (queue)
            {
                return Monitor.Wait(queue, timeout);
            }

        }

        public void Pulse()
        {
            lock (queue)
            {
                 Monitor.Pulse(queue);
            }

        }

        bool ICollection<T>.Contains(T item)
        {
            throw new NotImplementedException();
        }

        public void CopyTo(T[] array, int arrayIndex)
        {
            queue.CopyTo(array, arrayIndex);
        }

        public int Count
        {
            get { return count; }
        }

        bool ICollection<T>.IsReadOnly
        {
            get { return false; }
        }

        bool ICollection<T>.Remove(T item)
        {
            throw new NotImplementedException();
        }

        #endregion

        #region IEnumerable<T> Members

        /// <summary>
        /// Blocks if queue is empty.
        /// </summary>
        public IEnumerator<T> GetEnumerator()
        {
            while ( count > 0 ) yield return Dequeue();

        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
    #endregion

}
